%     AERO LOAD - программа для нагружения агрегатов самолета распределенной нагрузкой
%     Copyright (C) 2018-2024  Михаил Козлов
%     Сайт проекта: <http://www.fastenerdoctor.ru/>
%     Адрес электронной почты для связи с разработчиком:
%     <doctor.fastener@gmail.com>
% 
%     Эта программа является свободным программным обеспечением: Вы можете
%     распространять ее и/или изменять, соблюдая условия Универсальной общественной
%     лицензии GNU, опубликованной Фондом свободного программного обеспечения,
%     либо редакции 3, либо (на Ваше усмотрение) любой редакции, выпущенной позже.
% 
%     Эта программа распространяется в надежде на то, что она окажется полезной,
%     но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, включая даже подразумеваемую гарантию ТОВАРНОЙ ПРИГОДНОСТИ,
%     либо ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Ознакомьтесь с Универсальной общественной
%     лицензией GNU для получения более подробной информации.
% 
%     Вы должны были получить копию Универсальной общественной лицензии GNU
%     вместе с этой программой. Если Вы ее не получили, то перейдите по адресу:
%     <http://www.gnu.org/licenses/>.
% 
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
% 
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%     GNU General Public License for more details.
% 
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <https://www.gnu.org/licenses/>.

function Include_File(Fout, Directories_List, File_Name, Current_Depth_level)

global ErrCode;

% Максимальная глубина вложений команд INCLUDE
Max_Depth_level = 20;

% Максимальное число строк, которое может занимать имя файла в команде INCLUDE
Max_Include_Fname_Strings = 20;

% Проверка уровня вложения
if (Current_Depth_level > Max_Depth_level)
    fprintf (1, '\nОшибка: при выполнении команд INCLUDE достигнут максимальный уровень вложения [%i]!\n', Max_Depth_level);
    fprintf (1, 'Возможно, команды INCLUDE образуют бесконечный замкнутый цикл.\n');
    fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
    ErrCode = -1;
    return;
end

% Добавление к имени файла расширения при его отсутствии
temp_cell_array = strsplit(File_Name, {'/', '\'});
temp_fname = temp_cell_array{numel(temp_cell_array)};

if (isempty(strfind(temp_fname, '.'))) %#ok<STREMP> % Для совместимости с GNU Octave вместо if (~contains(fname, '.'))
    File_Name = [File_Name '.bdf'];
end

% Три случая
if ((length(File_Name) > 3) && isletter(File_Name(1)) && (File_Name(2) == ':') && ((File_Name(3) == '\') || (File_Name(3) == '/')))
    
    % --- Задан полный путь ---
    
    % Замена слешей на бэкслеши
    File_Path = strrep(File_Name, '/', '\');
    
    % Открытие файла
    Fin = fopen(File_Path, 'r');
    
else
    
    if ((~isempty(strfind(File_Name, '/'))) || (~isempty(strfind(File_Name, '\')))) %#ok<STREMP> % Для совместимости с GNU Octave вместо if (contains(File_Name, '/') || contains(File_Name, '\'))
        
        % --- Задан относительный путь (в этом случае просматривается только базовая директория) ---
        
        % Исключение первого символа
        if ((File_Name(1) == '\') || (File_Name(1) == '/'))
            File_Name = File_Name(2:length(File_Name));
        end
        
        % Добавление адреса базовой директории
        File_Path = [Directories_List{1} '\' File_Name];
        
        % Замена слешей на бэкслеши
        File_Path = strrep(File_Path, '/', '\');
        
        % Открытие файла
        Fin = fopen(File_Path, 'r');
        
    else
        
        % --- Задано только имя файла (в этом случае сначала просматривается базовая директория, а затем вся история директорий в обратном порядке) ---
        
        for i=1:numel(Directories_List)
            
            % Добавление полного пути к имени файла
            File_Path = [Directories_List{i} '\' File_Name];

            % Замена слешей на бэкслеши
            File_Path = strrep(File_Path, '/', '\');
            
            % Открытие файла
            Fin = fopen(File_Path, 'r');

            if (Fin >= 0)
                break;
            end
            
        end
        
    end
    
end

% Выдача сообщения об ошибке
if (Fin < 0)
    fprintf (1, '\nНе удалось открыть файл [%s] !\n', File_Path);
    ErrCode = -1;
    return;
end

% Получение директории открытого файла
temp_cell_array = strsplit(File_Path, {'/', '\'});
temp_fname = temp_cell_array{numel(temp_cell_array)};
if (length(File_Path) - length(temp_fname) - 1 < 1)
    fprintf (1, '\nОшибка функции Include_File: недопустимая длина имени директории открытого файла!\n');
    fprintf (1, 'Обратитесь к разработчику для решения этого вопроса.\n');
    ErrCode = -1;
    return;
end
Opened_File_Work_Dir = File_Path(1:length(File_Path) - length(temp_fname) - 1);

% Добавление директории открытого файла в список директорий
Tmp_Directories_List = cell(numel(Directories_List)+1,1);

Tmp_Directories_List{1,1} = Directories_List{1,1}; % Базовая директория
Tmp_Directories_List{2,1} = Opened_File_Work_Dir; % Директория открытого файла

if (numel(Directories_List) >= 2)
    Tmp_Directories_List(3:numel(Directories_List)+1,1) = Directories_List(2:numel(Directories_List),1);
end

Directories_List = Tmp_Directories_List;

% Копирование содержимого файла в Fout
Check_Empty_File = 1;

while (~feof(Fin))
    
    string = fgets(Fin);
    
    % Случай пустого файла
    if (Check_Empty_File == 1)
        if (isnumeric(string))
            break;
        else
            Check_Empty_File = 0;
        end
    end
    
    trimmed_string = strtrim(string);
    
    if (~isempty(trimmed_string))
        
        % Поиск команды INCLUDE
        if ((trimmed_string(1) == 'I') || (trimmed_string(1) == 'i'))
            if ((length(trimmed_string) >= 4) && strcmpi(trimmed_string(2:4), 'NCL'))

                % Исключение команды INCLUDE из строки
                temp_cell_array = strsplit(trimmed_string, {' ', '\t', ''''});

                switch upper(temp_cell_array{1})
                    case 'INCL'
                        if (length(trimmed_string) == 4)
                            fprintf (1, '\nОшибка функции Include_File: обнаружена команда INCLUDE с пустым параметром filename !\n');
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end
                        trimmed_string = trimmed_string(5:length(trimmed_string));
                        trimmed_string = strtrim(trimmed_string);
                    case 'INCLU'
                        if (length(trimmed_string) == 5)
                            fprintf (1, '\nОшибка функции Include_File: обнаружена команда INCLUDE с пустым параметром filename !\n');
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end
                        trimmed_string = trimmed_string(6:length(trimmed_string));
                        trimmed_string = strtrim(trimmed_string);
                    case 'INCLUD'
                        if (length(trimmed_string) == 6)
                            fprintf (1, '\nОшибка функции Include_File: обнаружена команда INCLUDE с пустым параметром filename !\n');
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end
                        trimmed_string = trimmed_string(7:length(trimmed_string));
                        trimmed_string = strtrim(trimmed_string);
                    case 'INCLUDE'
                        if (length(trimmed_string) == 7)
                            fprintf (1, '\nОшибка функции Include_File: обнаружена команда INCLUDE с пустым параметром filename !\n');
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end
                        trimmed_string = trimmed_string(8:length(trimmed_string));
                        trimmed_string = strtrim(trimmed_string);
                    otherwise
                        fprintf (1, '\nОшибка функции Include_File: неизвестная команда в bdf файле [%s] !\n', temp_cell_array{1});
                        fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                        ErrCode = -1;
                        fclose(Fin);
                        return;
                end

                % Обнаружение открывающей кавычки
                if (trimmed_string(1) == '''')
                    Quotation_Mark_flag = 1;
                else
                    Quotation_Mark_flag = 0;
                end

                switch Quotation_Mark_flag

                    case 0

                        if (~isempty(strfind(trimmed_string, ''''))) %#ok<STREMP> % Для совместимости с GNU Octave вместо if (contains(trimmed_string, ''''))
                            fprintf (1, '\nОшибка функции Include_File: не обнаружено открывающей кавычки в параметре filename команды INCLUDE !\n');
                            fprintf (1, '[%s]\n', Trim_CR_LF(string));
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end

                        Include_fname = trimmed_string;

                    case 1

                        % Ошибка в случае ''
                        if ((length(trimmed_string) >= 2) && strcmp(trimmed_string(1:2), ''''''))
                            fprintf (1, '\nОшибка функции Include_File: обнаружена команда INCLUDE с пустым параметром filename !\n');
                            fprintf (1, '[%s]\n', Trim_CR_LF(string));
                            fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                            ErrCode = -1;
                            fclose(Fin);
                            return;
                        end

                        % Обрезка открывающей кавычки
                        if (length(trimmed_string) == 1)
                            trimmed_string = [];
                        else
                            trimmed_string = trimmed_string(2:length(trimmed_string));
                        end

                        % Инициализация переменной
                        Include_fname = [];

                        % Инициализация счетчика строк
                        Include_Fname_Strings_counter = 1;

                        while(1)

                            if (Include_Fname_Strings_counter > Max_Include_Fname_Strings)
                                fprintf (1, '\nОшибка функции Include_File: параметр filename команды INCLUDE занимает более %i строк:\n', Max_Include_Fname_Strings);
                                fprintf (1, '[%s]\n', Include_fname);
                                fprintf (1, 'Возможно, в параметре filename команды INCLUDE отсутствует завершающая кавычка.\n');
                                fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                                ErrCode = -1;
                                fclose(Fin);
                                return;
                            end

                            if (~isempty(trimmed_string))

                                temp_k = strfind(trimmed_string, '''');

                                if (isempty(temp_k))

                                    Include_fname = [Include_fname trimmed_string]; %#ok<AGROW>

                                else

                                    if (numel(temp_k) ~= 1)
                                        fprintf (1, '\nОшибка функции Include_File: обнаружено более одной завершающей кавычки в параметре filename команды INCLUDE !\n');
                                        fprintf (1, '[%s]\n', trimmed_string);
                                        fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                                        ErrCode = -1;
                                        fclose(Fin);
                                        return;
                                    end

                                    if (trimmed_string(length(trimmed_string)) ~= '''')
                                        fprintf (1, '\nОшибка функции Include_File: неправильное положение завершающей кавычки в параметре filename команды INCLUDE !\n');
                                        fprintf (1, '[%s]\n', trimmed_string);
                                        fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                                        ErrCode = -1;
                                        fclose(Fin);
                                        return;
                                    end

                                    if (length(trimmed_string) > 1)
                                        Include_fname = [Include_fname trimmed_string(1:length(trimmed_string)-1)]; %#ok<AGROW>
                                        Include_fname = strtrim(Include_fname);
                                    end

                                    break;

                                end

                            end

                            if (feof(Fin))
                                fprintf (1, '\nОшибка функции Include_File: достигнут конец файла при чтении параметра filename команды INCLUDE !\n');
                                fprintf (1, '[%s]\n', Include_fname);
                                fprintf (1, 'Внесите исправления в bdf файл или обратитесь к разработчику для решения этого вопроса.\n');
                                ErrCode = -1;
                                fclose(Fin);
                                return;
                            end

                            string = fgets(Fin);
                            trimmed_string = strtrim(string);

                            Include_Fname_Strings_counter = Include_Fname_Strings_counter + 1;

                        end

                end

                % Вызов рекурсивной процедуры
                Include_File(Fout, Directories_List, Include_fname, Current_Depth_level+1);

                if (ErrCode < 0)
                    fclose(Fin);
                    return;
                end

                continue;

            end
        end
    
    end
    
    % Копирование строки
    fprintf (Fout, '%s\n', Trim_CR_LF(string));
    
end

% Закрытие файла
fclose(Fin);
